/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS  
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). 
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.  
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR  
 * COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND  
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE  
 * MAY BE CONSIDERED TO BE A CONTRACT,
 * THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED 
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 */
package lineage.controller;

import java.sql.Timestamp;

import lineage.core.L1GameClient;
import lineage.database.tables.bean.L1Account;
import lineage.packet.L1AbstractPacketServer;
import lineage.packet.server.S_Announcements;
import lineage.packet.server.S_LoginResult;
import lineage.packet.shared.CS_CharList;
import lineage.txt.L1Announcements;
import lineage.util.DateTimeUtil;

/**
 * 登入控制器.
 * 
 * @version 2014年3月13日下午8:09:40
 * @author jrwz
 */
public final class L1LoginController {
    /** 允许使用的字符(账号). */
    private static final String CHECK_ACCOUNT = "abcdefghijklmnopqrstuvwxyz0123456789";
    /** 允许使用的字符(密码). */
    private static final String CHECK_PASSWORD = "abcdefghijklmnopqrstuvwxyz0123456789!_=+-?.#";
    /** 帐号密码的长度-最小. */
    private static final int MIN = 5;
    /** 帐号密码的长度-最大. */
    private static final int MAX = 12;

    /**
     * 静态初始化器，由JVM来保证线程安全.
     */
    private static class Holder {
        static L1LoginController instance = new L1LoginController();
    }

    /**
     * 取得该类的实例.
     */
    public static L1LoginController getInstance() {
        return Holder.instance;
    }

    private L1LoginController() {
    }

    /**
     * 检查是否合法.
     * 
     * @param client
     *            - 客户端对象
     * @param accountName
     *            - 账号名称
     * @param password
     *            - 密码
     */
    public void execute(final L1GameClient client, final String accountName, final String password) {
        boolean flag = true;
        if (accountName == null) {
            return;
        }
        if (password == null) {
            return;
        }
        if (accountName.equalsIgnoreCase("")) {
            flag = false;
        }
        if (password.equalsIgnoreCase("")) {
            flag = false;
        }

        // 检查账号
        if (accountName.length() < MIN || accountName.length() > MAX) {
            flag = false;
        }
        for (int i = 0; i < accountName.length(); i++) {
            final String a = accountName.substring(i, i + 1);
            if (!CHECK_ACCOUNT.contains(a)) {
                flag = false;
            }
        }

        // 检查密码
        if (password.length() < MIN || password.length() > MAX) {
            flag = false;
        }
        for (int i = 0; i < password.length(); i++) {
            final String p = password.substring(i, i + 1);
            if (!CHECK_PASSWORD.contains(p)) {
                flag = false;
            }
        }

        if (flag) {
            auth(client, accountName, password);
        } else {
            sendPacket(client, new S_LoginResult(S_LoginResult.EVENT_PASSWORD_ERROR_CHECK));
        }
    }

    /**
     * 验证账号密码的正确性.
     * 
     * @param client
     *            - 客户端对象
     * @param accountName
     *            - 账号名称
     * @param password
     *            - 密码
     */
    private void auth(final L1GameClient client, final String accountName, final String password) {
        final boolean isAccount = L1AccountController.getInstance().isAccount(accountName);
        if (isAccount) { // 有该账号
            final boolean isLogin = L1AccountController.getInstance().isPassword(accountName, password);
            if (!isLogin) { // 密码错误
                sendPacket(client, new S_LoginResult(S_LoginResult.EVENT_PASSWORD_ERROR));
                return;
            }
        } else { // 没有该账号
            // TODO 是否能自动注册账号的验证
            // 创建账号
            L1AccountController.getInstance().addAccount(client, accountName, password);
        }
        isEnterGame(client, accountName, password);
    }

    /**
     * 检测能否进游戏.
     * 
     * @param client
     *            - 客户端对象
     * @param accountName
     *            - 账号名称
     * @param password
     *            - 密码
     */
    private void isEnterGame(final L1GameClient client, final String accountName, final String password) {
        // TODO 相关检查
        final boolean isOnline = L1AccountController.getInstance().isOnline(accountName);
        if (isOnline) { // 已经在线
            sendPacket(client, new S_LoginResult(S_LoginResult.REASON_ACCOUNT_IN_USE));
        } else {
            enterGame(client, accountName, password);
        }
    }

    /**
     * 完全通过验证后的相关设置.
     * 
     * @param client
     *            - 客户端对象
     * @param accountName
     *            - 账号名称
     * @param password
     *            - 密码
     */
    private void enterGame(final L1GameClient client, final String accountName, final String password) {
        // TODO 相关设置
        final boolean flag = L1AccountController.getInstance().add(accountName); // 加入在线账号列表内
        if (flag) { // 成功加入在线列表内
            client.setAccountName(accountName);
            L1Account account = L1AccountController.getInstance().getOnlineAccount(accountName);
            client.setAccount(account);

            sendPacket(client, new S_LoginResult(S_LoginResult.REASON_LOGIN_OK));

            final String msg = L1Announcements.getInstance().getMessage();
            if (!msg.isEmpty()) {
                sendPacket(client, new S_Announcements(msg)); // 发送公告
            } else {
                CS_CharList charList = new CS_CharList();
                charList.execute(client, null); // 发送角色列表
            }

            final Timestamp ts = DateTimeUtil.getTimestampMillis();
            L1AccountController.getInstance().updateLastDate(client, ts); // 更新最后登入日期
            L1AccountController.getInstance().updateLastIP(client); // 更新最后登入的ip地址
        } else {
            sendPacket(client, new S_LoginResult(S_LoginResult.EVENT_LAN_ERROR));
        }
    }

    /**
     * 向客户端发送封包.
     * 
     * @param client
     *            - 客户端对象
     * @param packet
     *            - 要发送的封包
     */
    private void sendPacket(final L1GameClient client, final L1AbstractPacketServer packet) {
        client.sendPacket(packet);
    }
}
